package com.agent.impl;

import com.agent.MovieRecommendationAgent;
import com.entity.view.MianfeiCollectionView;
import com.entity.view.MianfeiView;
import com.service.MianfeiCollectionService;
import com.service.MianfeiService;
import com.utils.PageUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 基于用户收藏记录的免费电影推荐智能体。
 */
@Component
public class MianfeiRecommendationAgent implements MovieRecommendationAgent {

    private final MianfeiCollectionService mianfeiCollectionService;
    private final MianfeiService mianfeiService;

    public MianfeiRecommendationAgent(MianfeiCollectionService mianfeiCollectionService,
                                      MianfeiService mianfeiService) {
        this.mianfeiCollectionService = mianfeiCollectionService;
        this.mianfeiService = mianfeiService;
    }

    @Override
    public List<MianfeiView> recommendByCollections(Map<String, Object> params, Integer userId) {
        int limit = resolveLimit(params);
        Set<Integer> collectedMovieIds = new HashSet<>();
        List<MianfeiCollectionView> collectionViewsList = Collections.emptyList();

        if (userId != null) {
            Map<String, Object> collectionParams = buildCollectionQuery(params, userId);
            PageUtils collectionPage = mianfeiCollectionService.queryPage(collectionParams);
            collectionViewsList = castCollectionList(collectionPage.getList());
            collectedMovieIds = collectionViewsList.stream()
                    .map(MianfeiCollectionView::getMianfeiId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
        }

        Map<Integer, Integer> typeScore = scoreTypes(collectionViewsList);
        List<Integer> sortedTypes = typeScore.entrySet().stream()
                .sorted((o1, o2) -> o2.getValue() - o1.getValue())
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        List<MianfeiView> recommendations = new ArrayList<>();
        Set<Integer> addedIds = new HashSet<>();
        for (Integer type : sortedTypes) {
            if (type == null) {
                continue;
            }
            List<MianfeiView> viewList = queryMoviesByType(params, type, limit);
            appendRecommendations(viewList, recommendations, addedIds, collectedMovieIds, limit);
            if (recommendations.size() >= limit) {
                return trimToLimit(recommendations, limit);
            }
        }

        // 若收藏记录不足，则使用系统默认的热门影片补足
        List<MianfeiView> fallbackList = queryDefaultMovies(params, limit);
        appendRecommendations(fallbackList, recommendations, addedIds, collectedMovieIds, limit);

        return trimToLimit(recommendations, limit);
    }

    @SuppressWarnings("unchecked")
    private List<MianfeiCollectionView> castCollectionList(List<?> list) {
        if (list == null) {
            return Collections.emptyList();
        }
        return (List<MianfeiCollectionView>) list;
    }

    private int resolveLimit(Map<String, Object> params) {
        Object limitObj = params.get("limit");
        if (limitObj == null) {
            return 10;
        }
        try {
            return Math.max(Integer.parseInt(String.valueOf(limitObj)), 1);
        } catch (NumberFormatException e) {
            return 10;
        }
    }

    private Map<String, Object> buildCollectionQuery(Map<String, Object> params, Integer userId) {
        Map<String, Object> query = new HashMap<>();
        query.put("page", 1);
        query.put("limit", 1000);
        query.put("sort", "id");
        query.put("order", "desc");
        query.put("yonghuId", userId);
        query.put("mianfeiDeleteStart", 1);
        query.put("mianfeiDeleteEnd", 1);
        Object collectionType = params.get("mianfeiCollectionTypes");
        if (collectionType != null) {
            query.put("mianfeiCollectionTypes", collectionType);
        }
        return query;
    }

    private Map<Integer, Integer> scoreTypes(List<MianfeiCollectionView> collectionViewsList) {
        Map<Integer, Integer> typeScore = new HashMap<>();
        for (MianfeiCollectionView view : collectionViewsList) {
            Integer type = view.getMianfeiTypes();
            if (type == null) {
                continue;
            }
            typeScore.put(type, typeScore.getOrDefault(type, 0) + 1);
        }
        return typeScore;
    }

    @SuppressWarnings("unchecked")
    private List<MianfeiView> queryMoviesByType(Map<String, Object> params, Integer type, int limit) {
        Map<String, Object> query = buildBaseMovieQuery(params, limit);
        query.put("mianfeiTypes", type);
        PageUtils moviePage = mianfeiService.queryPage(query);
        return (List<MianfeiView>) moviePage.getList();
    }

    @SuppressWarnings("unchecked")
    private List<MianfeiView> queryDefaultMovies(Map<String, Object> params, int limit) {
        Map<String, Object> query = buildBaseMovieQuery(params, limit);
        PageUtils moviePage = mianfeiService.queryPage(query);
        return (List<MianfeiView>) moviePage.getList();
    }

    private Map<String, Object> buildBaseMovieQuery(Map<String, Object> params, int limit) {
        Map<String, Object> query = new HashMap<>(params);
        query.put("page", 1);
        query.put("limit", limit);
        query.put("sort", params.getOrDefault("sort", "mianfeiClicknum"));
        query.put("order", params.getOrDefault("order", "desc"));
        query.put("mianfeiDeleteStart", 1);
        query.put("mianfeiDeleteEnd", 1);
        return query;
    }

    private void appendRecommendations(List<MianfeiView> source,
                                       List<MianfeiView> target,
                                       Set<Integer> addedIds,
                                       Set<Integer> collectedIds,
                                       int limit) {
        if (source == null) {
            return;
        }
        for (MianfeiView view : source) {
            if (view == null || view.getId() == null) {
                continue;
            }
            Integer movieId = view.getId();
            if (addedIds.contains(movieId) || collectedIds.contains(movieId)) {
                continue;
            }
            target.add(view);
            addedIds.add(movieId);
            if (target.size() >= limit) {
                return;
            }
        }
    }

    private List<MianfeiView> trimToLimit(List<MianfeiView> recommendations, int limit) {
        if (recommendations.size() <= limit) {
            return recommendations;
        }
        return recommendations.subList(0, limit);
    }
}

